﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Web;
using System.Web.Mvc;

namespace Inovout.Web.Mvc.Html
{
    /// <summary>
    /// Wiget模型元数据辅助类
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    public class WigetModelMetadataHelper<TModel> : BaseWigetModelMetadataHelper<TModel>, IHtmlString
    {
        private readonly Func<IHtmlString> toHtmlString;
        private WidgetModelPropertyCollectionMetadataHelper<TModel> propertyCollectionHelper;

        public WigetModelMetadataHelper(Func<IHtmlString> toHtmlString, WidgetModelMetadata metadata)
            : base(metadata)
        {
            this.toHtmlString = toHtmlString;
            this.propertyCollectionHelper = new WidgetModelPropertyCollectionMetadataHelper<TModel>(metadata);
        }
        public string ToHtmlString()
        {
            var proeprtyMetadatas = propertyCollectionHelper.Select(p => p.WidgetModelMetadata);
            if (proeprtyMetadatas.Any())
            {
                this.WidgetModelMetadata.SetSelectedModelDeclaringTypeProperties(proeprtyMetadatas.ToArray());
            }
            return this.toHtmlString().ToHtmlString();
        }
        /// <summary>
        /// 构建属性配置
        /// </summary>
        /// <param name="builder">构建方法</param>
        /// <returns></returns>
        public virtual WigetModelMetadataHelper<TModel> Build(Action<WidgetModelPropertyCollectionMetadataHelper<TModel>> builder)
        {
            builder(this.propertyCollectionHelper);

            return this;
        }
    }
    public class WidgetModelPropertyCollectionMetadataHelper<TModel> : BaseWigetModelMetadataHelper<TModel>, IEnumerable<IWidgetModelPropertyMetadataHelper<TModel>>
    {
        public WidgetModelPropertyCollectionMetadataHelper(WidgetModelMetadata metadata)
            : base(metadata)
        {
            this.propertiesHelpers = new List<IWidgetModelPropertyMetadataHelper<TModel>>();
        }
        private List<IWidgetModelPropertyMetadataHelper<TModel>> propertiesHelpers;
        /// <summary>
        /// 增加所有模型声明类型属性
        /// </summary>
        public void AddAllModelDeclaringTypeProperties()
        {
            var properties = this.WidgetModelMetadata.ModelDeclaringTypeProperties.Select((proeprtyMetadata) =>
            new WidgetModelPropertyMetadataHelper<TModel>(proeprtyMetadata.AsWidgetModelMetadata()));
            this.propertiesHelpers.AddRange(properties);
        }
        /// <summary>
        /// 增加属性
        /// </summary>
        /// <typeparam name="TProperty">属性类型</typeparam>
        /// <param name="expression">属性访问表达式</param>
        /// <returns>WidgetModelPropertyMetadataHelper对象实例</returns>
        public WidgetModelPropertyMetadataHelper<TModel, TProperty> Add<TProperty>(Expression<Func<TModel, TProperty>> expression)
        {
            WidgetModelMetadata proeprtyMetadata = this.WidgetModelMetadata.ModelDeclaringTypeProperties.Single(p => p.PropertyName.Equals(ExpressionHelper.GetExpressionText(expression))).AsWidgetModelMetadata();
            var property = new WidgetModelPropertyMetadataHelper<TModel, TProperty>(proeprtyMetadata);
            this.propertiesHelpers.Add(property);
            return property;
        }
        /// <summary>
        /// 扩展一个列，是模型没有对应的属性
        /// </summary>
        /// <param name="title">列标题</param>
        /// <param name="renderAsFuncs">呈现方法</param>
        /// <returns>WidgetModelPropertyMetadataHelper对象实例</returns>
        public WidgetModelPropertyMetadataHelper<TModel, TModel> Extend(string title, params Func<TModel, object>[] renderAsFuncs)
        {
            WidgetModelMetadata proeprtyMetadata =
                new WidgetModelMetadata((CachedDataAnnotationsModelMetadataProvider)ModelMetadataProviders.Current, null, typeof(TModel),
                "Extenssion-" + Guid.NewGuid().ToString(), Enumerable.Empty<Attribute>());
            proeprtyMetadata.DisplayName = title;
            proeprtyMetadata.TemplateHint = "Html";
            var property = new WidgetModelPropertyMetadataHelper<TModel, TModel>(proeprtyMetadata);

            if (renderAsFuncs.Length == 1)
            {
                property.RenderAs(renderAsFuncs[0]);
            }
            else
            {
                property.RenderAs(m =>
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var func in renderAsFuncs)
                    {
                        sb.Append(func(m).ToString());
                    }
                    return sb.ToString();
                });
            }
            this.propertiesHelpers.Add(property);
            return property;
        }
        public IEnumerator<IWidgetModelPropertyMetadataHelper<TModel>> GetEnumerator()
        {
            return this.propertiesHelpers.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
    }
    public interface IWidgetModelPropertyMetadataHelper<TModel>
    {
        string PropertyName { get; }

        WidgetModelMetadata WidgetModelMetadata { get; }
    }
    public class WidgetModelPropertyMetadataHelper<TModel> : BaseWigetModelMetadataHelper<TModel>, IWidgetModelPropertyMetadataHelper<TModel>
    {
        public WidgetModelPropertyMetadataHelper(WidgetModelMetadata metadata)
            : base(metadata)
        {
        }
        public string PropertyName { get { return this.WidgetModelMetadata.PropertyName; } }
    }
    public class WidgetModelPropertyMetadataHelper<TModel, TProperty> : WidgetModelPropertyMetadataHelper<TModel>
    {
        public WidgetModelPropertyMetadataHelper(WidgetModelMetadata metadata)
            : base(metadata)
        {
        }
        public WidgetModelPropertyMetadataHelper<TModel, TProperty> RenderAs(Func<TProperty, object> renderAsFunc)
        {
            this.WidgetModelMetadata.RenderAsFunc = (v) => renderAsFunc((TProperty)v);
            return this;
        }
        /// <summary>
        /// 网络列数量
        /// </summary>
        /// <param name="gridColumnCount"></param>
        /// <returns></returns>
        public WidgetModelPropertyMetadataHelper<TModel, TProperty> GridColumnCount(int gridColumnCount)
        {
            this.WidgetModelMetadata.GridColumnCount = gridColumnCount;
            return this;
        }
    }
    public abstract class BaseWigetModelMetadataHelper<TModel>
    {
        public WidgetModelMetadata WidgetModelMetadata { get; private set; }
        protected BaseWigetModelMetadataHelper(WidgetModelMetadata metadata)
        {
            this.WidgetModelMetadata = metadata;
        }
    }

}
